﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using Microsoft.Office.Interop.Word;
using WordShape = Microsoft.Office.Interop.Word.Shape;
using MsoShapeType = Microsoft.Office.Core.MsoShapeType;

namespace WPSPropertyPlugin.Shapes
{
  public class WordShapeObjectConfig
  {
    public string Name { get; set; }
    public string Guid { get; set; }
    public IDictionary Config { get; set; }
  }

  public class WordShapeObject : IOfficeShape
  {
    public static void Reset()
    {
      _globalShapeConfigs = null;
    }

    public static string GetShapeConfigByName(string shapeName)
    {
      return GlobalShapeConfigs[shapeName]?.Config;
    }

    private static IDictionary<string, WordShapeObject> _globalShapeConfigs = null;
    private static IDictionary<string, WordShapeObject> GlobalShapeConfigs
    {
      get
      {
        if (_globalShapeConfigs == null)
        {
          //初始化
          _globalShapeConfigs = new Dictionary<string, WordShapeObject>();
          var configData = ConfigFileName.ReadJSON<Dictionary<string, WordShapeObjectConfig>>();
          if (configData != null)
          {
            foreach (var item in configData)
            {
              _globalShapeConfigs.Add(item.Value.Name, new WordShapeObject(item.Value));
            }

            ForEachShape((shape) =>
            {
              if(_globalShapeConfigs.TryGetValue(shape.Name, out var shapeObject))
              {
                shapeObject.ShapeObject = shape;
              }
              return true;
            }, WPPPlugin.WPSApplication.WordApplication.ActiveDocument.Shapes);
          }
        }
        return _globalShapeConfigs;
      }
    }

    private static string ConfigFileName
    {
      get
      {
        var docPath = WPPPlugin.WPSApplication.WordApplication.ActiveDocument.FullName;
        var docFileInfo = new FileInfo(docPath);
        return $"{docFileInfo.DirectoryName}/{docFileInfo.Name}.json";
      }
    }

    public static IOfficeShape GetShapeObject(Selection selection)
    {
      WordShape shape = null;
      try
      {
        if (selection.ShapeRange.Count > 0)
        {
          shape = selection.ShapeRange[1];
          if (shape.GroupItems.Count > 0)
          {
            for (int i = 1; i <= shape.GroupItems.Count; i++)
            {
              var groupItem = shape.GroupItems[i];
              WordShape groupShapeItem = null;
              switch (groupItem.Type)
              {
                case MsoShapeType.msoChart:
                case MsoShapeType.msoPicture:
                  groupShapeItem = groupItem;
                  break;
              }
              if (groupShapeItem != null)
              {
                shape = groupShapeItem;
                break;
              }
            }
          }
        }
        else if (selection.InlineShapes.Count > 0)
        {
          var inlineShape = selection.InlineShapes[1];
          shape = inlineShape.ConvertToShape();
        }
        else if (selection.Tables.Count > 0)
        {
          //var table = selection.Tables[1];
          //MessageBox.Show(table.Descr);
          //table.ID = "007";
          //table.Title = "Fuck you!";
          //table.Descr = "Test!";
        }
      }
      catch { }
      if (shape != null)
      {
        try
        {
          var shapeName = shape.Name;
          var hasShape = GlobalShapeConfigs.TryGetValue(shapeName, out var officeShapeObject);
          if (officeShapeObject != null)
          {
            if (officeShapeObject.ShapeObject == null)
            {
              var findShape = FindShapeByName(shapeName, WPPPlugin.WPSApplication.WordApplication.ActiveDocument.Shapes);
              if (findShape != null)
              {
                officeShapeObject.ShapeObject = findShape;
              }
            }
            if (officeShapeObject.ShapeObject != null && officeShapeObject.ShapeObject.ID != shape.ID)
            {
              //如果出现了重名，那么自动名称索引加一
              shapeName = shapeName.AddNameIndex();
              hasShape = false;
            }
          }
          if (!hasShape)
          {
            officeShapeObject = new WordShapeObject
            {
              Guid = System.Guid.NewGuid().ToString().ToLower(),
              Name = shapeName,
              ShapeObject = shape
            };
            GlobalShapeConfigs.Add(shapeName, officeShapeObject);
          }
          if (officeShapeObject.ShapeObject == null)
          {
            officeShapeObject.ShapeObject = shape;
          }
          return officeShapeObject;
        }
        catch (Exception ex)
        {
          Console.WriteLine(ex.Message);
        }
      }
      return null;
    }

    public static bool ForEachShape(Func<WordShape, bool> handler, IEnumerable shapes)
    {
      foreach (WordShape findShape in shapes)
      {
        if (handler(findShape) == false)
        {
          return false;
        }
        try
        {
          if (findShape.GroupItems.Count > 0)
          {
            if (ForEachShape(handler, findShape.GroupItems) == false)
            {
              return false;
            }
          }
        }
        catch { }
      }
      return true;
    }

    public static WordShape FindShapeByName(string name, IEnumerable shapes)
    {
      foreach (WordShape findShape in shapes)
      {
        if (findShape.Name == name)
        {
          return findShape;
        }
        else
        {
          try
          {
            if (findShape.GroupItems.Count > 0)
            {
              //如果是组合对象，则在组合对象的子节点下查找
              var findGroupItem = FindShapeByName(name, findShape.GroupItems);
              if (findGroupItem != null)
              {
                return findGroupItem;
              }
            }
          }
          catch { }
        }
      }
      return null;
    }

    public WordShapeObject()
    {
    }

    public WordShapeObject(WordShapeObjectConfig configData)
    {
      this.Name = configData.Name;
      this.Guid = configData.Guid;
      this.Config = configData.Config.ToJSON();
    }

    private WordShapeObject(object shapeObject)
    {
      ShapeObject = shapeObject;
    }

    private dynamic _shapeObject = null;
    private dynamic ShapeObject
    {
      get
      {
        return _shapeObject;
      }
      set
      {
        _shapeObject = value;
        if (_shapeObject != null)
        {
          _shapeObject.Name = this.Name;
        }
      }
    }

    private string _name = null;
    public string Name
    {
      get
      {
        return _name;
      }
      set
      {
        if (ShapeObject != null)
        {
          ShapeObject.Name = value;
        }
        _name = value;
      }
    }

    public string Guid { get; set; }

    public string Config { get; set; }

    public void Delete() { }

    public void SaveConfig()
    {
      var configFileName = ConfigFileName;
      var fileInfo = new FileInfo(configFileName);
      if (!fileInfo.Directory.Exists)
      {
        fileInfo.Directory.Create();
      }
      var configData = new Dictionary<string, object>();
      foreach (var item in GlobalShapeConfigs)
      {
        if (string.IsNullOrEmpty(item.Value.Config) || item.Value.Config.Trim() == "{}")
        {
          continue;
        }
        configData.Add(item.Value.Name, new
        {
          item.Value.Name,
          item.Value.Guid,
          Config = item.Value.Config.ToDictionary()
        });
      }
      File.WriteAllText(configFileName, configData.ToJSON());
    }
  }
}
